msg_tool\scripts\qlie\archive\pack/
encryption.rs

1use super::delphi::*;
2use super::twister::*;
3use super::types::*;
4use crate::ext::io::*;
5use crate::scripts::base::*;
6use crate::types::*;
7use crate::utils::encoding::*;
8use crate::utils::mmx::*;
9use anyhow::Result;
10use pelite::FileMap;
11use pelite::pe32::{Pe, PeFile};
12use std::io::{Read, Seek, SeekFrom, Write};
13use std::path::{Path, PathBuf};
14
15pub trait Hasher {
16    fn update(&mut self, data: &[u8]) -> Result<()>;
17    fn finalize(&mut self) -> Result<u32>;
18}
19
20pub trait Encryption: std::fmt::Debug {
21    fn is_unicode(&self) -> bool {
22        false
23    }
24    fn compute_hash(&self, _data: &[u8]) -> Result<u32> {
25        Ok(0)
26    }
27    fn create_hash(&self) -> Result<Box<dyn Hasher>> {
28        Err(anyhow::anyhow!("Hasher not implemented"))
29    }
30    fn decrypt_name(&self, name: &mut [u8], hash: i32, encoding: Encoding) -> Result<String>;
31    fn decrypt_entry<'a>(
32        &self,
33        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
34        entry: &QlieEntry,
35    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>>;
36    fn index_has_hash(&self) -> bool {
37        true
38    }
39}
40
41pub fn create_encryption(
42    major: u8,
43    minor: u8,
44    game_key: Option<Vec<u8>>,
45) -> Result<Box<dyn Encryption + Send + Sync>> {
46    match (major, minor) {
47        (3, 1) => Ok(Box::new(Encryption31::new())),
48        (3, 0) => Ok(Box::new(Encryption30::new(game_key))),
49        (2, 0) => Ok(Box::new(Encryption20::new())),
50        (1, 0) => Ok(Box::new(Encryption10::new())),
51        _ => Err(anyhow::anyhow!(
52            "Unsupported encryption version: {}.{}",
53            major,
54            minor
55        )),
56    }
57}
58
59pub fn decompress<'a>(
60    data: Box<dyn ReadDebug + Send + Sync + 'a>,
61) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
62    Ok(Box::new(Decompressor::new(data)?))
63}
64
65pub fn decrypt(data: &mut [u8], key: u32) -> Result<()> {
66    let length = data.len();
67    if length < 8 {
68        // Nothing to decrypt
69        return Ok(());
70    }
71    let mut data = MemWriterRef::new(data);
72    const C1: u64 = 0xA73C5F9D;
73    const C2: u64 = 0xCE24F523;
74    const C3: u64 = 0xFEC9753E;
75    let mut v5 = mmx_punpckldq2(C1);
76    const V7: u64 = mmx_punpckldq2(C2);
77    let mut v9 = mmx_punpckldq2(((length as u32).wrapping_add(key) as u64) ^ C3);
78    for _ in 0..length / 8 {
79        let d = data.peek_u64()?;
80        v5 = mmx_p_add_d(v5, V7) ^ v9;
81        v9 = d ^ v5;
82        data.write_u64(v9)?;
83    }
84    Ok(())
85}
86
87pub fn encrypt(data: &mut [u8], key: u32) -> Result<()> {
88    let length = data.len();
89    if length < 8 {
90        // Nothing to encrypt
91        return Ok(());
92    }
93    let mut data = MemWriterRef::new(data);
94    const C1: u64 = 0xA73C5F9D;
95    const C2: u64 = 0xCE24F523;
96    const C3: u64 = 0xFEC9753E;
97    let mut v5 = mmx_punpckldq2(C1);
98    const V7: u64 = mmx_punpckldq2(C2);
99    let mut v9 = mmx_punpckldq2(((length as u32).wrapping_add(key) as u64) ^ C3);
100    for _ in 0..length / 8 {
101        let mut d = data.peek_u64()?;
102        v5 = mmx_p_add_d(v5, V7) ^ v9;
103        v9 = d;
104        d ^= v5;
105        data.write_u64(d)?;
106    }
107    Ok(())
108}
109
110pub fn get_common_key(data: &[u8]) -> Result<Vec<u8>> {
111    let mut reader = MemReaderRef::new(data);
112    let mut key = vec![0u8; 0x400];
113    let mut writer = MemWriterRef::new(&mut key);
114    for i in 0..0x100i32 {
115        let temp = if (i % 3) != 0 {
116            (i + 7) * -(i + 3)
117        } else {
118            (i + 7) * (i + 3)
119        };
120        writer.write_u32_at(i as u64 * 4, temp as u32)?;
121    }
122    let mut v1 = (reader.peek_u8_at(49)? % 0x49) as i32 + 0x80;
123    let v2 = (reader.peek_u8_at(79)? % 7) as i32 + 7;
124    let data_len = data.len() as i32;
125    for i in 0..0x400 {
126        v1 = (v1.wrapping_add(v2)) % data_len;
127        key[i] ^= reader.peek_u8_at(v1 as u64)?;
128    }
129    // crate::utils::files::write_file("./testscripts/test.bin")?.write_all(&key)?;
130    Ok(key)
131}
132
133#[derive(Debug)]
134pub struct Encryption31 {}
135
136impl Encryption31 {
137    pub fn new() -> Self {
138        Self {}
139    }
140
141    fn create_table(length: usize, mut value: u32, is_v1: bool) -> Result<Vec<u8>> {
142        let mut table = Vec::with_capacity(length);
143        let key: u32 = if is_v1 { 0x8DF21431 } else { 0x8A77F473 };
144        for _ in 0..length {
145            let t = (key as u64).wrapping_mul((value as u64) ^ (key as u64));
146            value = ((t >> 32) + t) as u32;
147            table.push(value);
148        }
149        let mut mem = MemWriter::with_capacity(length * 4);
150        for i in table {
151            mem.write_u32(i)?;
152        }
153        Ok(mem.into_inner())
154    }
155
156    pub fn compute_name_hash(&self, name: &[u16]) -> Result<u32> {
157        let mut v2 = 0u32;
158        let mut v3 = name.len() as u32;
159        let mut v4 = 1u32;
160        if v3 > 0 {
161            loop {
162                let n = (name[(v4 - 1) as usize] as u32) << (v4 & 7);
163                v2 = v2.wrapping_add(n) & 0x3FFFFFFF;
164                v4 += 1;
165                v3 -= 1;
166                if v3 == 0 {
167                    break;
168                }
169            }
170        }
171        Ok(v2)
172    }
173
174    pub fn encrypt_name(&self, name: &mut [u8], hash: i32) -> Result<()> {
175        if name.len() % 2 != 0 {
176            return Err(anyhow::anyhow!(
177                "Invalid name length for Unicode encryption"
178            ));
179        }
180        let char_len = name.len() / 2;
181        let cl = char_len as i32;
182        let temp = (cl.wrapping_mul(cl) ^ cl ^ 0x3e13 ^ (hash >> 16) ^ hash) & 0xFFFF;
183        let mut key = temp;
184        for i in 0..char_len {
185            key = temp
186                .wrapping_add(i as i32)
187                .wrapping_add(key.wrapping_mul(8));
188            name[i * 2] ^= key as u8;
189            name[i * 2 + 1] ^= (key >> 8) as u8;
190        }
191        Ok(())
192    }
193}
194
195impl Encryption for Encryption31 {
196    fn is_unicode(&self) -> bool {
197        true
198    }
199    fn compute_hash(&self, data: &[u8]) -> Result<u32> {
200        let mut hasher = Encryption31Hasher::new();
201        hasher.update(data)?;
202        Ok(hasher.finalize()?)
203    }
204    fn create_hash(&self) -> Result<Box<dyn Hasher>> {
205        Ok(Box::new(Encryption31Hasher::new()))
206    }
207    fn decrypt_name(&self, name: &mut [u8], hash: i32, _encoding: Encoding) -> Result<String> {
208        if name.len() % 2 != 0 {
209            return Err(anyhow::anyhow!(
210                "Invalid name length for Unicode decryption"
211            ));
212        }
213        let char_len = name.len() / 2;
214        let cl = char_len as i32;
215        let temp = (cl.wrapping_mul(cl) ^ cl ^ 0x3e13 ^ (hash >> 16) ^ hash) & 0xFFFF;
216        let mut key = temp;
217        for i in 0..char_len {
218            key = temp
219                .wrapping_add(i as i32)
220                .wrapping_add(key.wrapping_mul(8));
221            name[i * 2] ^= key as u8;
222            name[i * 2 + 1] ^= (key >> 8) as u8;
223        }
224        Ok(decode_to_string(Encoding::Utf16LE, &name, true)?)
225    }
226    fn decrypt_entry<'a>(
227        &self,
228        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
229        entry: &QlieEntry,
230    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
231        match entry.is_encrypted {
232            // No encryption
233            0 => Ok(Box::new(stream)),
234            1 => Ok(Box::new(Encryption31DecryptV1::new(
235                stream,
236                entry.size,
237                entry.name.clone(),
238                entry.key,
239            )?)),
240            2 => Ok(Box::new(Encryption31DecryptV2::new(
241                stream,
242                entry.size,
243                entry.name.clone(),
244                entry.key,
245                entry
246                    .common_key
247                    .clone()
248                    .ok_or(anyhow::anyhow!("Missing common key"))?,
249            )?)),
250            _ => Err(anyhow::anyhow!(
251                "Unsupported encryption flag: {}",
252                entry.is_encrypted
253            )),
254        }
255    }
256}
257
258pub struct Encryption31Hasher {
259    hash: u64,
260    key: u64,
261    buffer: [u8; 8],
262    buffer_len: usize,
263}
264
265impl Encryption31Hasher {
266    pub fn new() -> Self {
267        Self {
268            hash: 0,
269            key: 0,
270            buffer: [0; 8],
271            buffer_len: 0,
272        }
273    }
274
275    fn update_internal(&mut self, data: u64) {
276        const C: u64 = mmx_punpckldq2(0xA35793A7);
277        self.hash = mmx_p_add_w(self.hash, C);
278        let temp = mmx_p_add_w(self.key, self.hash ^ data);
279        self.key = mmx_p_sll_d(temp, 3) | mmx_p_srl_d(temp, 0x1d);
280    }
281}
282
283impl Hasher for Encryption31Hasher {
284    fn update(&mut self, data: &[u8]) -> Result<()> {
285        let mut used = 0;
286        if self.buffer_len > 0 {
287            let to_copy = (8 - self.buffer_len).min(data.len());
288            self.buffer[self.buffer_len..self.buffer_len + to_copy]
289                .copy_from_slice(&data[..to_copy]);
290            self.buffer_len += to_copy;
291            used += to_copy;
292        }
293        if self.buffer_len == 8 {
294            let v = u64::from_le_bytes(self.buffer);
295            self.update_internal(v);
296            self.buffer_len = 0;
297        }
298        let round = (data.len() - used) / 8;
299        let mut reader = MemReaderRef::new(&data[used..]);
300        for _ in 0..round {
301            let v = reader.read_u64()?;
302            self.update_internal(v);
303            used += 8;
304        }
305        let remaining = data.len() - used;
306        if remaining > 0 {
307            self.buffer[..remaining].copy_from_slice(&data[used..]);
308            self.buffer_len = remaining;
309        }
310        Ok(())
311    }
312
313    fn finalize(&mut self) -> Result<u32> {
314        let p1 = ((self.key as i16) as i32).wrapping_mul(((self.key >> 32) as i16) as i32);
315        let p2 = (((self.key >> 16) as i16) as i32).wrapping_mul(((self.key >> 48) as i16) as i32);
316        Ok((p1.wrapping_add(p2)) as u32)
317    }
318}
319
320#[derive(Debug)]
321struct Encryption31DecryptV1<'a> {
322    stream: Box<dyn ReadSeek + Send + Sync + 'a>,
323    table: MemReader,
324    v4: u32,
325    v6: u64,
326}
327
328impl<'a> Encryption31DecryptV1<'a> {
329    pub fn new(
330        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
331        size: u32,
332        name: String,
333        key: u32,
334    ) -> Result<AlignedReader<8, Self>> {
335        let mut v1 = 0x85F532u32;
336        let mut v2 = 0x33F641u32;
337        for (i, n) in name.encode_utf16().enumerate() {
338            v1 = v1.wrapping_add((n as u32) << (i & 7));
339            v2 ^= v1;
340        }
341        v2 = v2.wrapping_add(
342            key ^ ((7 * (size & 0xFFFFFF))
343                .wrapping_add(size)
344                .wrapping_add(v1)
345                .wrapping_add(v1 ^ size ^ 0x8F32DC)),
346        );
347        v2 = 9 * (v2 & 0xFFFFFF);
348        let table = MemReader::new(Encryption31::create_table(0x40, v2, true)?);
349        let v4 = 8 * (table.cpeek_u32_at(52)? & 0xF);
350        let v6 = table.cpeek_u64_at(24)?;
351        let inner = Self {
352            stream,
353            table,
354            v4,
355            v6,
356        };
357        Ok(AlignedReader::new(inner))
358    }
359}
360
361impl<'a> Read for Encryption31DecryptV1<'a> {
362    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
363        let readed = self.stream.read_most(buf)?;
364        let round = readed / 8;
365        let mut writer = MemWriterRef::new(buf);
366        for _ in 0..round {
367            let d = writer.peek_u64()?;
368            let temp = self.table.cpeek_u64_at(self.v4 as u64)?;
369            let v7 = mmx_p_add_d(self.v6 ^ temp, temp);
370            let v8 = d ^ v7;
371            writer.write_u64(v8)?;
372            self.v6 = mmx_p_add_w(mmx_p_sll_d(mmx_p_add_b(v7, v8) ^ v8, 1), v8);
373            self.v4 = (self.v4 + 8) & 0x7F;
374        }
375        Ok(readed)
376    }
377}
378
379#[derive(Debug)]
380pub struct Encryption31EncryptV1<T: Write> {
381    stream: T,
382    table: MemReader,
383    v4: u32,
384    v6: u64,
385}
386
387impl<T: Write> Encryption31EncryptV1<T> {
388    pub fn new(stream: T, size: u32, name: String, key: u32) -> Result<AlignedWriter<8, Self>> {
389        let mut v1 = 0x85F532u32;
390        let mut v2 = 0x33F641u32;
391        for (i, n) in name.encode_utf16().enumerate() {
392            v1 = v1.wrapping_add((n as u32) << (i & 7));
393            v2 ^= v1;
394        }
395        v2 = v2.wrapping_add(
396            key ^ ((7 * (size & 0xFFFFFF))
397                .wrapping_add(size)
398                .wrapping_add(v1)
399                .wrapping_add(v1 ^ size ^ 0x8F32DC)),
400        );
401        v2 = 9 * (v2 & 0xFFFFFF);
402        let table = MemReader::new(Encryption31::create_table(0x40, v2, true)?);
403        let v4 = 8 * (table.cpeek_u32_at(52)? & 0xF);
404        let v6 = table.cpeek_u64_at(24)?;
405        let inner = Self {
406            stream,
407            table,
408            v4,
409            v6,
410        };
411        Ok(AlignedWriter::new(inner))
412    }
413}
414
415impl<T: Write> Write for Encryption31EncryptV1<T> {
416    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
417        let round = buf.len() / 8;
418        let mut reader = MemReaderRef::new(buf);
419        for _ in 0..round {
420            let d = reader.read_u64()?;
421            let temp = self.table.cpeek_u64_at(self.v4 as u64)?;
422            let v7 = mmx_p_add_d(self.v6 ^ temp, temp);
423            let v8 = d ^ v7;
424            self.stream.write_u64(v8)?;
425            self.v6 = mmx_p_add_w(mmx_p_sll_d(mmx_p_add_b(v7, d) ^ d, 1), d);
426            self.v4 = (self.v4 + 8) & 0x7F;
427        }
428        let remain = buf.len() % 8;
429        if remain > 0 {
430            self.stream.write_all(&buf[buf.len() - remain..])?;
431        }
432        Ok(buf.len())
433    }
434
435    fn flush(&mut self) -> std::io::Result<()> {
436        self.stream.flush()
437    }
438}
439
440#[derive(Debug)]
441struct Encryption31DecryptV2<'a> {
442    stream: Box<dyn ReadSeek + Send + Sync + 'a>,
443    table: MemReader,
444    v4: u32,
445    v6: u64,
446    common_key: MemReader,
447}
448
449impl<'a> Encryption31DecryptV2<'a> {
450    pub fn new(
451        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
452        size: u32,
453        name: String,
454        key: u32,
455        common_key: Vec<u8>,
456    ) -> Result<AlignedReader<8, Self>> {
457        let mut v1 = 0x86F7E2u32;
458        let mut v2 = 0x4437F1u32;
459        for (i, n) in name.encode_utf16().enumerate() {
460            v1 = v1.wrapping_add((n as u32) << (i & 7));
461            v2 ^= v1;
462        }
463        v2 = v2.wrapping_add(
464            key ^ ((13 * (size & 0xFFFFFF))
465                .wrapping_add(size)
466                .wrapping_add(v1)
467                .wrapping_add(v1 ^ size ^ 0x56E213)),
468        );
469        v2 = 13 * (v2 & 0xFFFFFF);
470        let table = MemReader::new(Encryption31::create_table(0x40, v2, false)?);
471        let v4 = 8 * (table.cpeek_u32_at(32)? & 0xD);
472        let v6 = table.cpeek_u64_at(24)?;
473        let inner = Self {
474            stream,
475            table,
476            v4,
477            v6,
478            common_key: MemReader::new(common_key),
479        };
480        Ok(AlignedReader::new(inner))
481    }
482}
483
484impl<'a> Read for Encryption31DecryptV2<'a> {
485    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
486        let readed = self.stream.read_most(buf)?;
487        let round = readed / 8;
488        let mut writer = MemWriterRef::new(buf);
489        for _ in 0..round {
490            let d = writer.peek_u64()?;
491            let temp_index1 = ((self.v4 & 0xF) * 8) as u64;
492            let temp_index2 = ((self.v4 & 0x7F) * 8) as u64;
493            let temp = self.table.cpeek_u64_at(temp_index1)?
494                ^ self.common_key.cpeek_u64_at(temp_index2)?;
495            let v7 = mmx_p_add_d(self.v6 ^ temp, temp);
496            let v8 = d ^ v7;
497            writer.write_u64(v8)?;
498            self.v6 = mmx_p_add_w(mmx_p_sll_d(mmx_p_add_b(v7, v8) ^ v8, 1), v8);
499            self.v4 = (self.v4 + 1) & 0x7F;
500        }
501        Ok(readed)
502    }
503}
504
505#[derive(Debug)]
506pub struct Encryption31EncryptV2<T: Write> {
507    stream: T,
508    table: MemReader,
509    v4: u32,
510    v6: u64,
511    common_key: MemReader,
512}
513
514impl<T: Write> Encryption31EncryptV2<T> {
515    pub fn new(
516        stream: T,
517        size: u32,
518        name: String,
519        key: u32,
520        common_key: Vec<u8>,
521    ) -> Result<AlignedWriter<8, Self>> {
522        let mut v1 = 0x86F7E2u32;
523        let mut v2 = 0x4437F1u32;
524        for (i, n) in name.encode_utf16().enumerate() {
525            v1 = v1.wrapping_add((n as u32) << (i & 7));
526            v2 ^= v1;
527        }
528        v2 = v2.wrapping_add(
529            key ^ ((13 * (size & 0xFFFFFF))
530                .wrapping_add(size)
531                .wrapping_add(v1)
532                .wrapping_add(v1 ^ size ^ 0x56E213)),
533        );
534        v2 = 13 * (v2 & 0xFFFFFF);
535        let table = MemReader::new(Encryption31::create_table(0x40, v2, false)?);
536        let v4 = 8 * (table.cpeek_u32_at(32)? & 0xD);
537        let v6 = table.cpeek_u64_at(24)?;
538        let inner = Self {
539            stream,
540            table,
541            v4,
542            v6,
543            common_key: MemReader::new(common_key),
544        };
545        Ok(AlignedWriter::new(inner))
546    }
547}
548
549impl<T: Write> Write for Encryption31EncryptV2<T> {
550    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
551        let round = buf.len() / 8;
552        let mut reader = MemReaderRef::new(buf);
553        for _ in 0..round {
554            let d = reader.read_u64()?;
555            let temp_index1 = ((self.v4 & 0xF) * 8) as u64;
556            let temp_index2 = ((self.v4 & 0x7F) * 8) as u64;
557            let temp = self.table.cpeek_u64_at(temp_index1)?
558                ^ self.common_key.cpeek_u64_at(temp_index2)?;
559            let v7 = mmx_p_add_d(self.v6 ^ temp, temp);
560            let v8 = d ^ v7;
561            self.stream.write_u64(v8)?;
562            self.v6 = mmx_p_add_w(mmx_p_sll_d(mmx_p_add_b(v7, d) ^ d, 1), d);
563            self.v4 = (self.v4 + 1) & 0x7F;
564        }
565        let remain = buf.len() % 8;
566        if remain > 0 {
567            self.stream.write_all(&buf[buf.len() - remain..])?;
568        }
569        Ok(buf.len())
570    }
571
572    fn flush(&mut self) -> std::io::Result<()> {
573        self.stream.flush()
574    }
575}
576
577#[derive(Debug)]
578pub struct Decompressor<'a> {
579    stream: Box<dyn ReadDebug + Send + Sync + 'a>,
580    is_16bit: bool,
581    temp: Vec<u8>,
582    buf: Vec<u8>,
583    buf_pos: usize,
584}
585
586impl<'a> Decompressor<'a> {
587    pub fn new(mut stream: Box<dyn ReadDebug + Send + Sync + 'a>) -> Result<Self> {
588        let sign = stream.read_u32()?;
589        if sign != 0xFF435031 {
590            return Err(anyhow::anyhow!("Invalid compression signature"));
591        }
592        let is_16bit = stream.read_u32()? & 1 != 0;
593        let _unpacked_size = stream.read_u32()?;
594        let temp = vec![0u8; 0x1000];
595        Ok(Self {
596            stream,
597            is_16bit,
598            temp,
599            buf: Vec::new(),
600            buf_pos: 0,
601        })
602    }
603
604    fn next_block(&mut self) -> Result<()> {
605        self.buf.clear();
606        self.buf_pos = 0;
607        let mut buf = [0u8; 1];
608        let readed = self.stream.read(&mut buf)?;
609        if readed == 0 {
610            return Ok(());
611        }
612        let mut buf_used = false;
613        let mut table = [[0u8; 2]; 0x100];
614        let mut i = 0u32;
615        while i < 0x100 {
616            let mut c = if !buf_used {
617                buf_used = true;
618                buf[0] as u32
619            } else {
620                self.stream.read_u8()? as u32
621            };
622            if c > 127 {
623                c -= 127;
624                while c > 0 {
625                    table[i as usize][0] = i as u8;
626                    c -= 1;
627                    i += 1;
628                }
629            }
630            c += 1;
631            while c > 0 && i < 0x100 {
632                table[i as usize][0] = self.stream.read_u8()?;
633                if i as u8 != table[i as usize][0] {
634                    table[i as usize][1] = self.stream.read_u8()?;
635                }
636                c -= 1;
637                i += 1;
638            }
639        }
640        let mut block_size = if self.is_16bit {
641            self.stream.read_u16()? as usize
642        } else {
643            self.stream.read_u32()? as usize
644        };
645        let mut temp_length = 0usize;
646        while block_size > 0 || temp_length > 0 {
647            let c = if temp_length > 0 {
648                temp_length -= 1;
649                self.temp[temp_length]
650            } else {
651                block_size -= 1;
652                self.stream.read_u8()?
653            };
654            if c == table[c as usize][0] {
655                self.buf.push(c);
656            } else {
657                self.temp[temp_length] = table[c as usize][1];
658                temp_length += 1;
659                self.temp[temp_length] = table[c as usize][0];
660                temp_length += 1;
661            }
662        }
663        Ok(())
664    }
665}
666
667impl<'a> Read for Decompressor<'a> {
668    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
669        let mut used = 0;
670        while used < buf.len() {
671            if self.buf_pos >= self.buf.len() {
672                self.next_block()
673                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
674                if self.buf.is_empty() {
675                    break;
676                }
677            }
678            let to_copy = (self.buf.len() - self.buf_pos).min(buf.len() - used);
679            buf[used..used + to_copy]
680                .copy_from_slice(&self.buf[self.buf_pos..self.buf_pos + to_copy]);
681            self.buf_pos += to_copy;
682            used += to_copy;
683        }
684        Ok(used)
685    }
686}
687
688pub struct Compressor<W: Write + Seek> {
689    stream: W,
690    buffer: Vec<u8>,
691    total_unpacked_size: u32,
692    is_finished: bool,
693}
694
695impl<W: Write + Seek> Compressor<W> {
696    pub fn new(mut stream: W) -> Result<Self> {
697        stream.write_u32(0xFF435031)?;
698        stream.write_u32(0)?;
699        stream.write_u32(0)?;
700        Ok(Self {
701            stream,
702            buffer: Vec::new(),
703            total_unpacked_size: 0,
704            is_finished: false,
705        })
706    }
707
708    pub fn finish(&mut self) -> Result<()> {
709        if self.is_finished {
710            return Ok(());
711        }
712        if !self.buffer.is_empty() {
713            self.flush_block()?;
714        }
715        let pos = self.stream.stream_position()?;
716        self.stream.seek(SeekFrom::Start(8))?;
717        self.stream.write_u32(self.total_unpacked_size)?;
718        self.stream.seek(SeekFrom::Start(pos))?;
719        self.is_finished = true;
720        Ok(())
721    }
722
723    fn flush_block(&mut self) -> Result<()> {
724        if self.buffer.is_empty() {
725            return Ok(());
726        }
727        let (table, data) = compress_algo(&self.buffer);
728
729        // Write table
730        write_table(&mut self.stream, &table)?;
731
732        // Write block size
733        self.stream.write_u32(data.len() as u32)?;
734        self.stream.write_all(&data)?;
735
736        self.total_unpacked_size += self.buffer.len() as u32;
737        self.buffer.clear();
738        Ok(())
739    }
740}
741
742impl<W: Write + Seek> Write for Compressor<W> {
743    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
744        let mut pos = 0;
745        while pos < buf.len() {
746            let space = 0x10000 - self.buffer.len();
747            let copy = space.min(buf.len() - pos);
748            self.buffer.extend_from_slice(&buf[pos..pos + copy]);
749            pos += copy;
750            if self.buffer.len() >= 0x10000 {
751                self.flush_block()
752                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
753            }
754        }
755        Ok(buf.len())
756    }
757
758    fn flush(&mut self) -> std::io::Result<()> {
759        self.stream.flush()
760    }
761}
762
763impl<W: Write + Seek> Drop for Compressor<W> {
764    fn drop(&mut self) {
765        let _ = self.finish();
766    }
767}
768
769fn write_table<W: Write>(writer: &mut W, table: &[[u8; 2]; 256]) -> Result<()> {
770    let mut i = 0;
771    while i < 256 {
772        // Count consecutive identities
773        let mut n_identities = 0;
774        let mut j = i;
775        while j < 256 && table[j][0] == j as u8 {
776            n_identities += 1;
777            j += 1;
778        }
779
780        if n_identities > 0 {
781            let k = n_identities.min(128);
782            if i + k == 256 {
783                writer.write_u8(127 + k as u8)?;
784                i += k;
785            } else {
786                writer.write_u8(127 + k as u8)?;
787                i += k;
788                // Write explicit
789                writer.write_u8(table[i][0])?;
790                if table[i][0] != i as u8 {
791                    writer.write_u8(table[i][1])?;
792                }
793                i += 1;
794            }
795        } else {
796            let mut count = 0;
797            let mut j = i;
798            while j < 256 && count < 128 {
799                if j + 1 < 256 && table[j][0] == j as u8 && table[j + 1][0] == (j + 1) as u8 {
800                    break;
801                }
802                count += 1;
803                j += 1;
804            }
805
806            writer.write_u8((count - 1) as u8)?;
807            for k in 0..count {
808                let curr = i + k;
809                writer.write_u8(table[curr][0])?;
810                if table[curr][0] != curr as u8 {
811                    writer.write_u8(table[curr][1])?;
812                }
813            }
814            i += count;
815        }
816    }
817    Ok(())
818}
819
820fn compress_algo(input: &[u8]) -> ([[u8; 2]; 256], Vec<u8>) {
821    let mut tokens = input.to_vec();
822    let mut table = [[0u8; 2]; 256];
823    for i in 0..256 {
824        table[i][0] = i as u8;
825    }
826
827    let max_iterations = 256;
828    for _ in 0..max_iterations {
829        let mut pair_counts = vec![0u32; 65536];
830        let mut max_pair_idx = 0;
831        let mut max_pair_count = 0;
832
833        if tokens.len() < 2 {
834            break;
835        }
836
837        for i in 0..tokens.len() - 1 {
838            let pair = ((tokens[i] as usize) << 8) | (tokens[i + 1] as usize);
839            pair_counts[pair] += 1;
840            if pair_counts[pair] > max_pair_count {
841                max_pair_count = pair_counts[pair];
842                max_pair_idx = pair;
843            }
844        }
845
846        // Must appear at least twice to save space (2 bytes * 2 -> 1 byte * 2 + overhead)
847        if max_pair_count < 2 {
848            break;
849        }
850
851        let is_used = get_used_tokens(&tokens, &table);
852        let mut unused = None;
853        for i in 0..256 {
854            if !is_used[i] {
855                unused = Some(i as u8);
856                break;
857            }
858        }
859
860        if let Some(token) = unused {
861            let left = (max_pair_idx >> 8) as u8;
862            let right = (max_pair_idx & 0xFF) as u8;
863
864            table[token as usize] = [left, right];
865
866            let mut new_tokens = Vec::with_capacity(tokens.len());
867            let mut i = 0;
868            while i < tokens.len() {
869                if i + 1 < tokens.len() && tokens[i] == left && tokens[i + 1] == right {
870                    new_tokens.push(token);
871                    i += 2;
872                } else {
873                    new_tokens.push(tokens[i]);
874                    i += 1;
875                }
876            }
877            tokens = new_tokens;
878        } else {
879            break;
880        }
881    }
882    (table, tokens)
883}
884
885fn get_used_tokens(tokens: &[u8], table: &[[u8; 2]; 256]) -> [bool; 256] {
886    let mut used = [false; 256];
887    let mut stack = Vec::with_capacity(256);
888
889    // Mark direct tokens
890    for &t in tokens {
891        if !used[t as usize] {
892            used[t as usize] = true;
893            stack.push(t);
894        }
895    }
896
897    // Propagate
898    while let Some(t) = stack.pop() {
899        // If t is composite, mark children
900        // Check if t is composite: table[t][0] != t
901        let t_idx = t as usize;
902        if table[t_idx][0] != t {
903            let l = table[t_idx][0];
904            let r = table[t_idx][1];
905
906            if !used[l as usize] {
907                used[l as usize] = true;
908                stack.push(l);
909            }
910            if !used[r as usize] {
911                used[r as usize] = true;
912                stack.push(r);
913            }
914        }
915    }
916    used
917}
918
919pub fn compress(data: &[u8]) -> Result<Vec<u8>> {
920    let mut cursor = std::io::Cursor::new(Vec::new());
921    {
922        let mut compressor = Compressor::new(&mut cursor)?;
923        compressor.write_all(data)?;
924        compressor.finish()?;
925    }
926    Ok(cursor.into_inner())
927}
928
929const KEY_DIR: [&'static str; 4] = [".", "..", "../DLL", "DLL"];
930
931pub fn find_game_key(filename: &str) -> Result<Option<Vec<u8>>> {
932    let path = PathBuf::from(filename);
933    if !path.is_file() {
934        return Ok(None);
935    }
936    if let Some(pdir) = path.parent() {
937        for dir in KEY_DIR {
938            let key_path = pdir.join(dir).join("key.fkey");
939            if key_path.is_file() {
940                eprintln!("Found res key file: {}", key_path.display());
941                return Ok(Some(std::fs::read(key_path)?));
942            }
943        }
944        let exe_dir = pdir.join("..");
945        if exe_dir.is_dir() {
946            for entry in std::fs::read_dir(exe_dir)? {
947                let entry = entry?;
948                if entry.file_type()?.is_file() {
949                    if let Some(ext) = entry.path().extension() {
950                        if ext.eq_ignore_ascii_case("exe") {
951                            if let Ok(key) = get_game_key_from_exe(&entry.path()) {
952                                eprintln!(
953                                    "Found res key in executable: {}",
954                                    entry.path().display()
955                                );
956                                return Ok(Some(key));
957                            }
958                        }
959                    }
960                }
961            }
962        }
963    }
964    Ok(None)
965}
966
967pub fn get_game_key_from_exe<S: AsRef<Path> + ?Sized>(exe_path: &S) -> Result<Vec<u8>> {
968    let path = exe_path.as_ref();
969    let file_map = FileMap::open(path)?;
970    let file = PeFile::from_bytes(&file_map)?;
971    let resources = file.resources()?;
972    Ok(resources
973        .find_resource(&["#10".into(), "RESKEY".into()])?
974        .to_vec())
975}
976
977pub fn find_key_data(filename: &str) -> Result<Option<Vec<u8>>> {
978    let path = PathBuf::from(filename);
979    if !path.is_file() {
980        return Ok(None);
981    }
982    if let Some(pdir) = path.parent() {
983        let exe_dir = pdir.join("..");
984        if exe_dir.is_dir() {
985            for entry in std::fs::read_dir(exe_dir)? {
986                let entry = entry?;
987                if entry.file_type()?.is_file() {
988                    if let Some(ext) = entry.path().extension() {
989                        if ext.eq_ignore_ascii_case("exe") {
990                            if let Ok(key) = get_key_data_from_exe(&entry.path()) {
991                                eprintln!(
992                                    "Found key data in executable: {}",
993                                    entry.path().display()
994                                );
995                                return Ok(Some(key));
996                            }
997                        }
998                    }
999                }
1000            }
1001        }
1002    }
1003    Ok(None)
1004}
1005
1006pub fn get_key_data_from_exe<S: AsRef<Path> + ?Sized>(exe_path: &S) -> Result<Vec<u8>> {
1007    let path = exe_path.as_ref();
1008    let file_map = FileMap::open(path)?;
1009    let file = PeFile::from_bytes(&file_map)?;
1010    let resources = file.resources()?;
1011    let key_data = resources.find_resource(&["#10".into(), "TFORM1".into()])?;
1012    let mut reader = MemReaderRef::new(&key_data);
1013    let form = deser_delphi(&mut reader)?;
1014    let image = form
1015        .contents
1016        .iter()
1017        .find(|s| s.name == "IconKeyImage")
1018        .ok_or(anyhow::anyhow!("IconKeyImage not found in form"))?;
1019    let picture_data = image
1020        .properties
1021        .get("Picture.Data")
1022        .ok_or(anyhow::anyhow!("Picture.Data not found in IconKeyImage"))?
1023        .as_bytes()
1024        .ok_or(anyhow::anyhow!("Picture.Data is not bytes"))?;
1025    let mut reader = MemReaderRef::new(picture_data);
1026    let mut sig = [0u8; 6];
1027    reader.read_exact(&mut sig)?;
1028    if &sig != b"\x05TIcon" {
1029        return Err(anyhow::anyhow!("Invalid TIcon signature"));
1030    }
1031    Ok(reader.read_exact_vec(0x100)?)
1032}
1033
1034#[derive(Debug)]
1035pub struct Encryption30 {
1036    key: Option<Vec<u8>>,
1037}
1038
1039impl Encryption30 {
1040    pub fn new(game_key: Option<Vec<u8>>) -> Self {
1041        Self { key: game_key }
1042    }
1043}
1044
1045impl Encryption for Encryption30 {
1046    fn decrypt_name(&self, name: &mut [u8], hash: i32, encoding: Encoding) -> Result<String> {
1047        let key = (hash ^ 0x3E) + name.len() as i32;
1048        for i in 1..=name.len() {
1049            name[i - 1] ^= ((key ^ i as i32).wrapping_add(i as i32)) as u8;
1050        }
1051        Ok(decode_to_string(encoding, name, true)?)
1052    }
1053
1054    fn create_hash(&self) -> Result<Box<dyn Hasher>> {
1055        Ok(Box::new(Encryption30Hasher::new()))
1056    }
1057
1058    fn compute_hash(&self, data: &[u8]) -> Result<u32> {
1059        let mut hasher = Encryption30Hasher::new();
1060        hasher.update(data)?;
1061        hasher.finalize()
1062    }
1063
1064    fn decrypt_entry<'a>(
1065        &self,
1066        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1067        entry: &QlieEntry,
1068    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
1069        if entry.is_encrypted == 0 {
1070            return Ok(Box::new(stream));
1071        }
1072        if self.key.is_none() || entry.common_key.is_none() {
1073            return Ok(Box::new(Decrypter::new(stream, entry.key, entry.size)));
1074        }
1075        return Ok(Box::new(Encryption30Decrypt::new(
1076            stream,
1077            &entry.raw_name,
1078            entry.common_key.as_ref().unwrap(),
1079            entry.size,
1080            entry.key,
1081            self.key.as_ref().unwrap(),
1082        )));
1083    }
1084}
1085
1086#[derive(Debug)]
1087pub struct Encryption30Hasher {
1088    hash: u64,
1089    key: u64,
1090    buffer: [u8; 8],
1091    buffer_len: usize,
1092}
1093
1094impl Encryption30Hasher {
1095    pub fn new() -> Self {
1096        Self {
1097            hash: 0,
1098            key: 0,
1099            buffer: [0; 8],
1100            buffer_len: 0,
1101        }
1102    }
1103
1104    fn update_internal(&mut self, data: u64) {
1105        const C: u64 = mmx_punpckldq2(0x03070307);
1106        self.hash = mmx_p_add_w(self.hash, C);
1107        self.key = mmx_p_add_w(self.key, self.hash ^ data);
1108    }
1109}
1110
1111impl Hasher for Encryption30Hasher {
1112    fn update(&mut self, data: &[u8]) -> Result<()> {
1113        let mut used = 0;
1114        if self.buffer_len > 0 {
1115            let to_copy = (8 - self.buffer_len).min(data.len());
1116            self.buffer[self.buffer_len..self.buffer_len + to_copy]
1117                .copy_from_slice(&data[..to_copy]);
1118            self.buffer_len += to_copy;
1119            used += to_copy;
1120        }
1121        if self.buffer_len == 8 {
1122            let v = u64::from_le_bytes(self.buffer);
1123            self.update_internal(v);
1124            self.buffer_len = 0;
1125        }
1126        let round = (data.len() - used) / 8;
1127        let mut reader = MemReaderRef::new(&data[used..]);
1128        for _ in 0..round {
1129            let v = reader.read_u64()?;
1130            self.update_internal(v);
1131            used += 8;
1132        }
1133        let remaining = data.len() - used;
1134        if remaining > 0 {
1135            self.buffer[..remaining].copy_from_slice(&data[used..]);
1136            self.buffer_len = remaining;
1137        }
1138        Ok(())
1139    }
1140
1141    fn finalize(&mut self) -> Result<u32> {
1142        let key = self.key ^ (self.key >> 32);
1143        Ok(key as u32)
1144    }
1145}
1146
1147#[derive(Debug)]
1148pub struct Decrypter<'a> {
1149    stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1150    v5: u64,
1151    v9: u64,
1152}
1153
1154impl<'a> Decrypter<'a> {
1155    pub fn new(
1156        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1157        key: u32,
1158        length: u32,
1159    ) -> AlignedReader<8, Self> {
1160        const C1: u64 = 0xA73C5F9D;
1161        const C3: u64 = 0xFEC9753E;
1162        const V5_INIT: u64 = mmx_punpckldq2(C1);
1163        let v9 = mmx_punpckldq2((length.wrapping_add(key) as u64) ^ C3);
1164        AlignedReader::new(Self {
1165            stream,
1166            v5: V5_INIT,
1167            v9,
1168        })
1169    }
1170}
1171
1172impl<'a> Read for Decrypter<'a> {
1173    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1174        let readed = self.stream.read_most(buf)?;
1175        let round = readed / 8;
1176        let mut writer = MemWriterRef::new(buf);
1177        const C2: u64 = 0xCE24F523;
1178        const V7: u64 = mmx_punpckldq2(C2);
1179        for _ in 0..round {
1180            let d = writer.peek_u64()?;
1181            self.v5 = mmx_p_add_d(self.v5, V7) ^ self.v9;
1182            self.v9 = d ^ self.v5;
1183            writer.write_u64(self.v9)?;
1184        }
1185        Ok(readed)
1186    }
1187}
1188
1189#[derive(Debug)]
1190struct Encryption30Decrypt<'a> {
1191    stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1192    table: [u64; 0x10],
1193    hash64: u64,
1194    t: usize,
1195}
1196
1197impl<'a> Encryption30Decrypt<'a> {
1198    pub fn new<'b>(
1199        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1200        raw_name: &'b [u8],
1201        common_key: &'b [u8],
1202        size: u32,
1203        key: u32,
1204        game_key: &'b [u8],
1205    ) -> AlignedReader<8, Self> {
1206        let mut hash = 0x85F532u32;
1207        let mut seed = 0x33F641u32;
1208        for (i, n) in raw_name.iter().enumerate() {
1209            hash = hash.wrapping_add(((i & 0xFF) as u32) * (*n as u32));
1210            seed ^= hash;
1211        }
1212        seed = seed.wrapping_add(
1213            key ^ ((7 * (size & 0xFFFFFF))
1214                .wrapping_add(size)
1215                .wrapping_add(hash)
1216                .wrapping_add(hash ^ size ^ 0x8F32DC)),
1217        );
1218        seed = 9 * (seed & 0xFFFFFF);
1219        seed ^= 0x453A;
1220        let mut mt = MersenneTwister::new(seed);
1221        if !common_key.is_empty() {
1222            mt.xor_state(common_key);
1223        }
1224        if !game_key.is_empty() {
1225            mt.xor_state(game_key);
1226        }
1227        let mut table = [0u64; 0x10];
1228        for i in 0..0x10 {
1229            table[i] = mt.rand64();
1230        }
1231        for _ in 0..9 {
1232            mt.rand();
1233        }
1234        let hash64 = mt.rand64();
1235        let t = mt.rand() as usize & 0xF;
1236        AlignedReader::new(Self {
1237            stream,
1238            table,
1239            hash64,
1240            t,
1241        })
1242    }
1243}
1244
1245impl<'a> Read for Encryption30Decrypt<'a> {
1246    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1247        let readed = self.stream.read_most(buf)?;
1248        let round = readed / 8;
1249        let mut writer = MemWriterRef::new(buf);
1250        for _ in 0..round {
1251            let data64 = writer.peek_u64()?;
1252            self.hash64 = mmx_p_add_d(self.hash64 ^ self.table[self.t], self.table[self.t]);
1253            let d = data64 ^ self.hash64;
1254            writer.write_u64(d)?;
1255            self.hash64 = mmx_p_add_b(self.hash64, d) ^ d;
1256            self.hash64 = mmx_p_add_w(mmx_p_sll_d(self.hash64, 1), d);
1257            self.t = (self.t + 1) & 0xF;
1258        }
1259        Ok(readed)
1260    }
1261}
1262
1263#[derive(Debug)]
1264pub struct Encryption10 {}
1265
1266impl Encryption10 {
1267    pub fn new() -> Self {
1268        Self {}
1269    }
1270}
1271
1272impl Encryption for Encryption10 {
1273    fn decrypt_name(&self, name: &mut [u8], _hash: i32, encoding: Encoding) -> Result<String> {
1274        const KEY: u32 = 0xC4 ^ 0x3E;
1275        for (i, b) in name.iter_mut().enumerate() {
1276            let i = (i + 1) as u32;
1277            *b ^= ((KEY ^ i).wrapping_add(i)) as u8;
1278        }
1279        decode_to_string(encoding, name, true)
1280    }
1281
1282    fn decrypt_entry<'a>(
1283        &self,
1284        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1285        entry: &QlieEntry,
1286    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
1287        if entry.is_encrypted == 0 {
1288            return Ok(Box::new(stream));
1289        }
1290        Ok(Box::new(Encryption10Decrypt::new(stream, 0)))
1291    }
1292
1293    fn index_has_hash(&self) -> bool {
1294        false
1295    }
1296}
1297
1298#[derive(Debug)]
1299pub struct Encryption20 {
1300    index_has_hash: bool,
1301}
1302
1303impl Encryption20 {
1304    pub fn new() -> Self {
1305        Self {
1306            index_has_hash: true,
1307        }
1308    }
1309
1310    pub fn new_no_hash() -> Self {
1311        Self {
1312            index_has_hash: false,
1313        }
1314    }
1315}
1316
1317impl Encryption for Encryption20 {
1318    fn decrypt_name(&self, name: &mut [u8], _hash: i32, encoding: Encoding) -> Result<String> {
1319        let key = (0xC4u32 ^ 0x3E).wrapping_add(name.len() as u32);
1320        for (i, b) in name.iter_mut().enumerate() {
1321            let i = (i + 1) as u32;
1322            *b ^= ((key ^ i).wrapping_add(i)) as u8;
1323        }
1324        decode_to_string(encoding, name, true)
1325    }
1326
1327    fn decrypt_entry<'a>(
1328        &self,
1329        stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1330        entry: &QlieEntry,
1331    ) -> Result<Box<dyn ReadDebug + Send + Sync + 'a>> {
1332        if entry.is_encrypted == 0 {
1333            return Ok(Box::new(stream));
1334        }
1335        Ok(Box::new(Decrypter::new(stream, 0, entry.size)))
1336    }
1337
1338    fn index_has_hash(&self) -> bool {
1339        self.index_has_hash
1340    }
1341}
1342
1343#[derive(Debug)]
1344struct Encryption10Decrypt<'a> {
1345    stream: Box<dyn ReadSeek + Send + Sync + 'a>,
1346    v5: u64,
1347    v9: u64,
1348}
1349
1350impl<'a> Encryption10Decrypt<'a> {
1351    pub fn new(stream: Box<dyn ReadSeek + Send + Sync + 'a>, key: u32) -> AlignedReader<8, Self> {
1352        const C1: u64 = 0xA73C5F9D;
1353        const C3: u64 = 0xFEC9753E;
1354        const V5_INIT: u64 = mmx_punpckldq2(C1);
1355        let v9 = mmx_punpckldq2((key as u64) ^ C3);
1356        AlignedReader::new(Self {
1357            stream,
1358            v5: V5_INIT,
1359            v9,
1360        })
1361    }
1362}
1363
1364impl<'a> Read for Encryption10Decrypt<'a> {
1365    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1366        let readed = self.stream.read_most(buf)?;
1367        let round = readed / 8;
1368        let mut writer = MemWriterRef::new(buf);
1369        const C2: u64 = 0xCE24F523;
1370        const V7: u64 = mmx_punpckldq2(C2);
1371        for _ in 0..round {
1372            let d = writer.peek_u64()?;
1373            self.v5 = mmx_p_add_d(self.v5, V7) ^ self.v9;
1374            self.v9 = d ^ self.v5;
1375            writer.write_u64(self.v9)?;
1376        }
1377        Ok(readed)
1378    }
1379}
1380
1381#[test]
1382fn test_compress_decompress() -> Result<()> {
1383    let data = b"The quick brown fox jumps over the lazy dog.".repeat(100);
1384    println!("Original size: {}", data.len());
1385    let compressed = compress(&data)?;
1386    println!("Compressed size: {}", compressed.len());
1387    let mut decompressed = decompress(Box::new(MemReaderRef::new(&compressed)))?;
1388    let mut output = Vec::new();
1389    decompressed.read_to_end(&mut output)?;
1390    assert_eq!(data.as_slice(), output.as_slice());
1391    Ok(())
1392}